﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;

namespace Jayden.Dll.Cards.Poker.PokerStars
{
	public class HistoryReader
	{

		public interface HistoryLineReader
		{
			Match Match(string input);
		}
		public class HistoryLineRegex : HistoryLineReader
		{
			private Regex[] m_Regexes = null;
			public HistoryLineRegex(params Regex[] regexes)
			{
				m_Regexes = regexes.Clone() as Regex[];
			}
			public HistoryLineRegex(params string[] pattern)
			{
				m_Regexes = new Regex[pattern.Length];
				for (int c = 0; c < m_Regexes.Length; c++)
					m_Regexes[c] = new Regex(pattern[c]);
			}

			public Regex[] Regexes { get { return m_Regexes; } }
			public Match Match(string input)
			{
				Match match = System.Text.RegularExpressions.Match.Empty;
				for (int c = 0; c < m_Regexes.Length; c++)
				{
					match = m_Regexes[c].Match(input);
					if (match.Success)
						return match;
				}
				return match;
			}

			public override string ToString() { return string.Join(" or ", m_Regexes.ToArray<object>()); }
		}
		#region Constants
		private const string ActionPrefix = @"(?<PlayerName>.*): ";
		private const string PlayerPrefix = @"(?<PlayerName>.*) ";
		private const string SeatPrefix = @"Seat (?<SeatNumber>\d*): " + PlayerPrefix;

		private const string HeaderZoomLinePattern = @"(?<ProviderName>.*) Zoom Hand #(?<HandReference>\d*):(?<GameType>.*)\((?<SmallBlind>.*)/(?<BigBlind>.*)\) \- (?<LocalDateTime>.*) CET \[(?<DateTime>.*) ET\]";
		private const string HeaderLinePattern = @"(?<ProviderName>.*) (Hand|Game) #(?<HandReference>\d*):(?<GameType>.*)\((?<SmallBlind>.*)/(?<BigBlind>.*) (?<Currency>.*)\) \- (?<LocalDateTime>.*) (?<TimeZone>...) \[(?<DateTime>.*) ET\]";
		private const string HeaderPlayMoneyLinePattern = @"(?<ProviderName>.*) (Hand|Game) #(?<HandReference>\d*):(?<GameType>.*)\((?<SmallBlind>.*)/(?<BigBlind>.*)\) \- (?<LocalDateTime>.*) (?<TimeZone>...) \[(?<DateTime>.*) ET\]";
		private const string TableLinePattern = @"Table '(?<TableName>.*)' (?<SeatCount>\d*)(.*) Seat #(?<DealerSeatNumber>\d*) is the button";
		private const string DealtHoleCardLinePattern = @"Dealt to (?<PlayerName>.*) \[(?<HoleCards>.*)\]";
		private const string TotalPotFullLinePattern = @"Total pot (?<Amount>.*) Main pot (?<Details>.*)\| Rake (?<RakeAmount>.*)";
		private const string TotalPotLinePattern = @"Total pot (?<Amount>.*) \| Rake (?<RakeAmount>.*)";
		private const string SummaryBoardLinePattern = @"Board \[(?<CommunityCards>.*)\]";
		private const string UncalledBetLinePattern = @"Uncalled bet \((?<Amount>.*)\) returned to (?<PlayerName>.*)";

		private const string SeatLinePattern = SeatPrefix + @"\((?<PlayerStack>.*) in chips\)";
		private const string MessageLinePattern = PlayerPrefix + @"said, ""(?<Text>.*)""";
		private const string PlayerPostsSmallBlindLinePattern = ActionPrefix + "posts small blind (?<Amount>.*)";
		private const string PlayerPostsBigBlindLinePattern = ActionPrefix + "posts big blind (?<Amount>.*)";
		private const string PlayerPostsAnteLinePattern = ActionPrefix + "posts the ante (?<Amount>.*)";
		private const string PlayerPostsBlindsLinePattern = ActionPrefix + "posts small & big blinds (?<Amount>.*)";
		private const string PlayerSitsOutLinePattern = ActionPrefix + "sits out";
		private const string PlayerWillBeAllowedToPlayAfterButtonLinePattern = PlayerPrefix + @"will be allowed to play after the button";
		private const string PlayerHasTimedOutLinePattern = PlayerPrefix + @"has timed out";
		private const string PlayerIsSittingOutLinePattern = PlayerPrefix + @"is sitting out";
		private const string PlayerFoldsLinePattern = ActionPrefix + "folds";
		private const string PlayerCallsLinePattern = ActionPrefix + "calls (?<Amount>.*)";
		private const string PlayerChecksLinePattern = ActionPrefix + "checks";
		private const string PlayerBetsLinePattern = ActionPrefix + "bets (?<Amount>.*)";
		private const string PlayerRaisesLinePattern = ActionPrefix + "raises (?<Amount>.*) to (?<BetAmount>.*)";
		private const string PlayerLeavesTableLinePattern = PlayerPrefix + @"leaves the table";
		private const string PlayerJoinsTableLinePattern = PlayerPrefix + @"joins the table at seat #(?<SeatNumber>\d*)";
		private const string PlayerCollectedFromPotLinePattern = PlayerPrefix + @"collected (?<Amount>.*) from pot";
		private const string PlayerCollectedFromMainPotLinePattern = PlayerPrefix + @"collected (?<Amount>.*) from main pot";
		private const string PlayerCollectedFromSidePotLinePattern = PlayerPrefix + @"collected (?<Amount>.*) from side pot";
		private const string PlayerShowsLinePattern = ActionPrefix + @"shows \[(?<HoleCards>.*)\] \((?<HandName>.*)\)";
		private const string PlayerShowsCardLinePattern = ActionPrefix + @"shows \[(?<HoleCards>.*)\]";
		private const string PlayerMucksLinePattern = ActionPrefix + "mucks hand";
		private const string PlayerDoesNotShowLinePattern = ActionPrefix + "doesn't show hand";
		private const string PlayerSittingOutLinePattern = ActionPrefix + "is sitting out";
		private const string PlayerDisconnectedLinePattern = PlayerPrefix + @"is disconnected";
		private const string PlayerConnectedLinePattern =PlayerPrefix + @"is connected";
		private const string PlayerReturnedLinePattern = PlayerPrefix + @"has returned";
		private const string PlayerRemovedFromTableLinePattern = PlayerPrefix + @"was removed from the table for failing to post";
		private const string PlayerFinishedTournamentLinePattern = PlayerPrefix + @"finished the tournament in (?<TournamentPlace>.*) place";
		private const string PlayerReBuysTournamentLinePattern = PlayerPrefix + @"re-buys and receives (?<ChipsCount>.*) chips for (?<Amount>.*)";

		private const string PlayerCallsAllInLinePattern = PlayerCallsLinePattern + " and is all-in";
		private const string PlayerBetsAllInLinePattern = PlayerBetsLinePattern + " and is all-in";
		private const string PlayerRaisesAllInLinePattern = PlayerRaisesLinePattern + " and is all-in";
		private const string PlayerPostsSmallBlindAllInLinePattern = PlayerPostsSmallBlindLinePattern + " and is all-in";
		private const string PlayerPostsBigBlindAllInLinePattern = PlayerPostsBigBlindLinePattern + " and is all-in";
		private const string PlayerPostsAnteAllInLinePattern = PlayerPostsAnteLinePattern + " and is all-in";

		private const int HoleCardsStreetIndex = 0;
		private const int FlopStreetIndex = 1;
		private const int TurnStreetIndex = 2;
		private const int RiverStreetIndex = 3;
		private const int ShowDownStreetIndex = 4;
		private const int SummaryStreetIndex = 5;
		private static readonly string[] StreetLinePatterns = new string[] 
		{
			@"\*\*\* HOLE CARDS \*\*\*",
			@"\*\*\* FLOP \*\*\* \[(?<FlopCards>.*)\]",
			@"\*\*\* TURN \*\*\* \[(?<CommunityCards>.*)\] \[(?<TurnCard>.*)\]",
			@"\*\*\* RIVER \*\*\* \[(?<CommunityCards>.*)\] \[(?<RiverCard>.*)\]",
			@"\*\*\* SHOW DOWN \*\*\*",
			@"\*\*\* SUMMARY \*\*\*"
		};
		#endregion
		private static string[] BuildSummaryPattern(string seatPrefix, string pattern)
		{
			return new string[]
			{
				//"Seat 6: TM Punk79 (button) folded before Flop (didn't bet)"
				seatPrefix + @"\(button\) \(small blind\) " + pattern,
				seatPrefix + @"\(small blind\) " + pattern,
				seatPrefix + @"\(big blind\) " + pattern,
				seatPrefix + @"\(button\) " + pattern,
				seatPrefix + pattern
			};
		}

		public static string[] BuildLinePatterns()
		{
			List<string> list = new List<string>(new string[]
			{
				SeatLinePattern,
				PlayerPostsAnteAllInLinePattern,
				PlayerPostsSmallBlindAllInLinePattern,
				PlayerPostsBigBlindAllInLinePattern,
				PlayerPostsSmallBlindLinePattern,
				PlayerPostsBigBlindLinePattern,
				PlayerPostsAnteLinePattern,
				PlayerPostsBlindsLinePattern,
				PlayerSitsOutLinePattern,
				PlayerFoldsLinePattern,
				PlayerCallsAllInLinePattern,
				PlayerCallsLinePattern,
				PlayerChecksLinePattern,
				PlayerBetsAllInLinePattern,
				PlayerBetsLinePattern,
				PlayerRaisesAllInLinePattern,
				PlayerRaisesLinePattern,
				PlayerShowsLinePattern,
				PlayerShowsCardLinePattern,
				PlayerMucksLinePattern,
				PlayerDoesNotShowLinePattern,
				PlayerSittingOutLinePattern,
				DealtHoleCardLinePattern,
				HeaderLinePattern,
				HeaderZoomLinePattern,
				HeaderPlayMoneyLinePattern,
				TableLinePattern,
				PlayerCollectedFromPotLinePattern,
				PlayerCollectedFromMainPotLinePattern,
				PlayerCollectedFromSidePotLinePattern,
				PlayerHasTimedOutLinePattern,
				PlayerIsSittingOutLinePattern,
				PlayerDisconnectedLinePattern,
				PlayerConnectedLinePattern,
				PlayerReturnedLinePattern,
				PlayerLeavesTableLinePattern,
				PlayerFinishedTournamentLinePattern,
				PlayerReBuysTournamentLinePattern,
				PlayerJoinsTableLinePattern,
				PlayerWillBeAllowedToPlayAfterButtonLinePattern,
				PlayerRemovedFromTableLinePattern,
				MessageLinePattern,
				UncalledBetLinePattern,
				TotalPotFullLinePattern,
				//TotalPotDoubleLinePattern,
				TotalPotLinePattern,
				SummaryBoardLinePattern
			});
			list.AddRange(StreetLinePatterns);
			list.AddRange(BuildSummaryPattern(SeatPrefix, @"folded before Flop \(didn't bet\)"));
			list.AddRange(BuildSummaryPattern(SeatPrefix, @"folded before Flop"));
			list.AddRange(BuildSummaryPattern(SeatPrefix, @"folded on the (?<StreetName>.*)"));
			list.AddRange(BuildSummaryPattern(SeatPrefix, @"mucked \[(?<HoleCards>.*)\]"));
			list.AddRange(BuildSummaryPattern(SeatPrefix, @"showed \[(?<HoleCards>.*)\] and won \((?<Amount>.*)\) with (?<HandName>.*)"));
			list.AddRange(BuildSummaryPattern(SeatPrefix, @"showed \[(?<HoleCards>.*)\] and lost with (?<HandName>.*)"));
			list.AddRange(BuildSummaryPattern(SeatPrefix, @"collected \((?<Amount>.*)\)"));

			return list.ToArray();
		}
		#region Regexes
		public static readonly HistoryLineRegex HeaderLineRegex = new HistoryLineRegex(HeaderLinePattern, HeaderPlayMoneyLinePattern, HeaderZoomLinePattern);
		public static readonly HistoryLineRegex TableLineRegex = new HistoryLineRegex(TableLinePattern);
		public static readonly HistoryLineRegex SeatLineRegex = new HistoryLineRegex(SeatLinePattern);
		public static readonly HistoryLineRegex MessageLineRegex = new HistoryLineRegex(MessageLinePattern);
		public static readonly HistoryLineRegex TotalPotLineRegex = new HistoryLineRegex(TotalPotFullLinePattern, /*TotalPotDoubleLinePattern, */TotalPotLinePattern);
		public static readonly HistoryLineRegex HoleCardStreetLineRegex = new HistoryLineRegex(StreetLinePatterns[HoleCardsStreetIndex]);
		public static readonly HistoryLineRegex FlopStreetLineRegex = new HistoryLineRegex(StreetLinePatterns[FlopStreetIndex]);
		public static readonly HistoryLineRegex TurnStreetLineRegex = new HistoryLineRegex(StreetLinePatterns[TurnStreetIndex]);
		public static readonly HistoryLineRegex RiverStreetLineRegex = new HistoryLineRegex(StreetLinePatterns[RiverStreetIndex]);
		public static readonly HistoryLineRegex ShowDownStreetLineRegex = new HistoryLineRegex(StreetLinePatterns[ShowDownStreetIndex]);
		public static readonly HistoryLineRegex SummaryStreetLineRegex = new HistoryLineRegex(StreetLinePatterns[SummaryStreetIndex]);
		public static readonly HistoryLineRegex PlayerPostsSmallBlindLineRegex = new HistoryLineRegex(PlayerPostsSmallBlindAllInLinePattern, PlayerPostsSmallBlindLinePattern);
		public static readonly HistoryLineRegex PlayerPostsBigBlindLineRegex = new HistoryLineRegex(PlayerPostsBigBlindAllInLinePattern, PlayerPostsBigBlindLinePattern);
		public static readonly HistoryLineRegex PlayerPostsBlindsLineRegex = new HistoryLineRegex(PlayerPostsBlindsLinePattern);
		public static readonly HistoryLineRegex PlayerPostsAnteLineRegex = new HistoryLineRegex(PlayerPostsAnteAllInLinePattern, PlayerPostsAnteLinePattern);
		public static readonly HistoryLineRegex PlayerWillBeAllowedToPlayAfterButtonLineRegex = new HistoryLineRegex(PlayerWillBeAllowedToPlayAfterButtonLinePattern);
		public static readonly HistoryLineRegex PlayerSitsOutLineRegex = new HistoryLineRegex(PlayerSitsOutLinePattern);
		public static readonly HistoryLineRegex PlayerHasTimedOutLineRegex = new HistoryLineRegex(PlayerHasTimedOutLinePattern);
		public static readonly HistoryLineRegex PlayerIsSittingOutLineRegex = new HistoryLineRegex(PlayerIsSittingOutLinePattern);
		public static readonly HistoryLineRegex DealtHoleCardLineRegex = new HistoryLineRegex(DealtHoleCardLinePattern);
		public static readonly HistoryLineRegex PlayerFoldsLineRegex = new HistoryLineRegex(PlayerFoldsLinePattern);
		public static readonly HistoryLineRegex PlayerCallsLineRegex = new HistoryLineRegex(PlayerCallsAllInLinePattern, PlayerCallsLinePattern);
		public static readonly HistoryLineRegex PlayerChecksLineRegex = new HistoryLineRegex(PlayerChecksLinePattern);
		public static readonly HistoryLineRegex PlayerBetsLineRegex = new HistoryLineRegex(PlayerBetsAllInLinePattern, PlayerBetsLinePattern);
		public static readonly HistoryLineRegex PlayerRaisesLineRegex = new HistoryLineRegex(PlayerRaisesAllInLinePattern, PlayerRaisesLinePattern);
		public static readonly HistoryLineRegex PlayerLeavesTableLineRegex = new HistoryLineRegex(PlayerLeavesTableLinePattern);
		public static readonly HistoryLineRegex PlayerJoinsTableLineRegex = new HistoryLineRegex(PlayerJoinsTableLinePattern);
		public static readonly HistoryLineRegex UncalledBetLineRegex = new HistoryLineRegex(UncalledBetLinePattern);
		public static readonly HistoryLineRegex PlayerCollectedFromPotLineRegex = new HistoryLineRegex(PlayerCollectedFromPotLinePattern);
		public static readonly HistoryLineRegex PlayerCollectedFromSidePotLineRegex = new HistoryLineRegex(PlayerCollectedFromSidePotLinePattern);
		public static readonly HistoryLineRegex PlayerCollectedFromMainPotLineRegex = new HistoryLineRegex(PlayerCollectedFromMainPotLinePattern);
		public static readonly HistoryLineRegex PlayerShowsLineRegex = new HistoryLineRegex(PlayerShowsLinePattern);
		public static readonly HistoryLineRegex PlayerShowsCardLineRegex = new HistoryLineRegex(PlayerShowsCardLinePattern);
		public static readonly HistoryLineRegex PlayerMucksLineRegex = new HistoryLineRegex(PlayerMucksLinePattern);
		public static readonly HistoryLineRegex PlayerDoesNotShowLineRegex = new HistoryLineRegex(PlayerDoesNotShowLinePattern);
		public static readonly HistoryLineRegex PlayerSittingOutLineRegex = new HistoryLineRegex(PlayerSittingOutLinePattern);
		public static readonly HistoryLineRegex PlayerDisconnectedLineRegex = new HistoryLineRegex(PlayerDisconnectedLinePattern);
		public static readonly HistoryLineRegex PlayerConnectedLineRegex = new HistoryLineRegex(PlayerConnectedLinePattern);
		public static readonly HistoryLineRegex PlayerReturnedLineRegex = new HistoryLineRegex(PlayerReturnedLinePattern);
		public static readonly HistoryLineReader PlayerRemovedFromTableLineRegex = new HistoryLineRegex(PlayerRemovedFromTableLinePattern);
		public static readonly HistoryLineReader PlayerFinishedTournamentLineRegex = new HistoryLineRegex(PlayerFinishedTournamentLinePattern);
		public static readonly HistoryLineReader PlayerReBuysTournamentLineRegex = new HistoryLineRegex(PlayerReBuysTournamentLinePattern);
		#endregion
		public static double ParseAmount(string value)
		{
			if (!char.IsDigit(value[0]))
				return double.Parse(value.Substring(1), CultureInfo.InvariantCulture);
			return double.Parse(value, CultureInfo.InvariantCulture);
		}

		public static Match ReadState(TexasHoldemHandSummaryLegacy summary, string line)
		{
			Match leaves = PlayerLeavesTableLineRegex.Match(line);
			if (leaves.Success)
				return leaves;
			Match joins = PlayerJoinsTableLineRegex.Match(line);
			if (joins.Success)
				return joins;
			Match timedOut = PlayerHasTimedOutLineRegex.Match(line);
			if (timedOut.Success)
				return timedOut;
			Match sittingOut = PlayerSittingOutLineRegex.Match(line);
			if (sittingOut.Success)
				return sittingOut;
			sittingOut = PlayerIsSittingOutLineRegex.Match(line);
			if (sittingOut.Success)
				return sittingOut;
			Match playerWillBeAllowedToPlayAfterButtonMatch = PlayerWillBeAllowedToPlayAfterButtonLineRegex.Match(line);
			if (playerWillBeAllowedToPlayAfterButtonMatch.Success)
				return playerWillBeAllowedToPlayAfterButtonMatch;
			Match playerSitsOut = PlayerSitsOutLineRegex.Match(line);
			if (playerSitsOut.Success)
				return playerSitsOut;
			Match disconnected = PlayerDisconnectedLineRegex.Match(line);
			if (disconnected.Success)
				return disconnected;
			Match connected = PlayerConnectedLineRegex.Match(line);
			if (connected.Success)
				return connected;
			Match returned = PlayerReturnedLineRegex.Match(line);
			if (returned.Success)
				return returned;
			Match removed = PlayerRemovedFromTableLineRegex.Match(line);
			if(removed.Success)
				return removed;
			return MessageLineRegex.Match(line);
		}
		public static Match ReadStartAction(TexasHoldemHandSummaryLegacy summary, string line)
		{
			Match smallBlindMatch = PlayerPostsSmallBlindLineRegex.Match(line);
			if (smallBlindMatch.Success)
			{
				summary.AddAction(smallBlindMatch.Groups["PlayerName"].Value, Enums.PokerActionType.SmallBlind, ParseAmount(smallBlindMatch.Groups["Amount"].Value));
				return smallBlindMatch;
			}
			Match bigBlindMatch = PlayerPostsBigBlindLineRegex.Match(line);
			if (bigBlindMatch.Success)
			{
				summary.AddAction(bigBlindMatch.Groups["PlayerName"].Value, Enums.PokerActionType.BigBlind, ParseAmount(bigBlindMatch.Groups["Amount"].Value));
				return bigBlindMatch;
			}
			Match blindsMatchs = PlayerPostsBlindsLineRegex.Match(line);
			if (blindsMatchs.Success)
			{
				summary.AddAction(blindsMatchs.Groups["PlayerName"].Value, Enums.PokerActionType.BothBlinds, ParseAmount(blindsMatchs.Groups["Amount"].Value));
				return blindsMatchs;
			}
			Match anteMatchs = PlayerPostsAnteLineRegex.Match(line);
			if (anteMatchs.Success)
			{
				summary.AddAction(anteMatchs.Groups["PlayerName"].Value, Enums.PokerActionType.Ante, ParseAmount(anteMatchs.Groups["Amount"].Value));
				return anteMatchs;
			}
			return ReadState(summary, line);
		}
		public static Match ReadAction(TexasHoldemHandSummaryLegacy summary, string line)
		{
			Match folds = PlayerFoldsLineRegex.Match(line);
			if (folds.Success)
			{
				summary.AddAction(folds.Groups["PlayerName"].Value, Enums.PokerActionType.Fold);
				return folds;
			}
			Match calls = PlayerCallsLineRegex.Match(line);
			if (calls.Success)
			{
				summary.AddAction(calls.Groups["PlayerName"].Value, Enums.PokerActionType.Call, ParseAmount(calls.Groups["Amount"].Value));
				return calls;
			}
			Match checks = PlayerChecksLineRegex.Match(line);
			if (checks.Success)
			{
				summary.AddAction(checks.Groups["PlayerName"].Value, Enums.PokerActionType.Check);
				return checks;
			}
			Match bets = PlayerBetsLineRegex.Match(line);
			if (bets.Success)
			{
				summary.AddAction(bets.Groups["PlayerName"].Value, Enums.PokerActionType.Bet, ParseAmount(bets.Groups["Amount"].Value));
				return bets;
			}
			Match raises = PlayerRaisesLineRegex.Match(line);
			if (raises.Success)
			{
				summary.AddAction(raises.Groups["PlayerName"].Value, Enums.PokerActionType.Raise, ParseAmount(raises.Groups["Amount"].Value));
				return raises;
			}
			Match rebuysTournament = PlayerReBuysTournamentLineRegex.Match(line);
			if (rebuysTournament.Success)
				return rebuysTournament;
			return ReadState(summary, line);
		}
		public static Match ReadShowAction(TexasHoldemHandSummaryLegacy summary, string line)
		{
			Match show = PlayerShowsLineRegex.Match(line);
			if (show.Success)
			{
				summary.SetHoleCards(show.Groups["PlayerName"].Value, Card.ParseArray(show.Groups["HoleCards"].Value));
				return show;
			}
			Match mucks = PlayerMucksLineRegex.Match(line);
			if (mucks.Success)
				return mucks;
			Match folds = PlayerFoldsLineRegex.Match(line);
			if (folds.Success)
			{
				summary.AddAction(folds.Groups["PlayerName"].Value, Enums.PokerActionType.Fold);
				return folds;
			}
			return ReadState(summary, line);
		}
		public static Match ReadEndAction(TexasHoldemHandSummaryLegacy summary, string line)
		{
			Match uncalled = UncalledBetLineRegex.Match(line);
			if (uncalled.Success)
			{
				summary.ReturnUncalledBet(uncalled.Groups["PlayerName"].Value, ParseAmount(uncalled.Groups["Amount"].Value));
				return uncalled;
			}
			Match collected = PlayerCollectedFromPotLineRegex.Match(line);
			if (collected.Success)
			{
				summary.Winnings.Add(new KeyValuePair<string, ulong>(collected.Groups["PlayerName"].Value, (ulong)Math.Round(ParseAmount(collected.Groups["Amount"].Value) * 100)));
				return collected;
			}
			Match collectedMain = PlayerCollectedFromMainPotLineRegex.Match(line);
			if (collectedMain.Success)
			{
				summary.Winnings.Add(new KeyValuePair<string, ulong>(collectedMain.Groups["PlayerName"].Value, (ulong)Math.Round(ParseAmount(collectedMain.Groups["Amount"].Value) * 100)));
				return collectedMain;
			}
			Match collectedSide = PlayerCollectedFromSidePotLineRegex.Match(line);
			if (collectedSide.Success)
			{
				summary.Winnings.Add(new KeyValuePair<string, ulong>(collectedSide.Groups["PlayerName"].Value, (ulong)Math.Round(ParseAmount(collectedSide.Groups["Amount"].Value) * 100)));
				return collectedSide;
			}
			Match doesNotShow = PlayerDoesNotShowLineRegex.Match(line);
			if (doesNotShow.Success)
				return doesNotShow;
			Match showCard = PlayerShowsCardLineRegex.Match(line);
			if (showCard.Success)
			{
				summary.SetHoleCards(showCard.Groups["PlayerName"].Value, Card.ParseArray(showCard.Groups["HoleCards"].Value));
				return showCard;
			}
			Match finishedTournament = PlayerFinishedTournamentLineRegex.Match(line);
			if (finishedTournament.Success)
				return finishedTournament;
			Match rebuysTournament = PlayerReBuysTournamentLineRegex.Match(line);
			if (rebuysTournament.Success)
				return rebuysTournament;
			return ReadShowAction(summary, line);
		}

		public static IEnumerable<TexasHoldemHandSummaryLegacy> Read(string[] lines)
		{
			int lineIndex = 0;
			while (lineIndex < lines.Length)
				yield return Read(lines, ref lineIndex);
		}
		public static TexasHoldemHandSummaryLegacy Read(string[] lines, ref int lineIndex)
		{
			Match headerMatch = HeaderLineRegex.Match(lines[lineIndex]);
			if (headerMatch.Success)
			{
				TexasHoldemHandSummaryLegacy summary = new TexasHoldemHandSummaryLegacy();
				summary.ProviderName = headerMatch.Groups["ProviderName"].Value;
				summary.HandReference = headerMatch.Groups["HandReference"].Value;
				summary.SmallBlind = (ulong)(ParseAmount(headerMatch.Groups["SmallBlind"].Value) * 100);
				summary.BigBlind = (ulong)(ParseAmount(headerMatch.Groups["BigBlind"].Value) * 100);
				if (headerMatch.Groups["Currency"] != null)
				{
					if(headerMatch.Groups["Currency"] != null)
						summary.Currency = headerMatch.Groups["Currency"].Value;
				}
				if (string.IsNullOrWhiteSpace(summary.Currency))
				{
					if (summary.ProviderName == "PokerStars Zoom")
						summary.Currency = "USD";
					else
						summary.Currency = "";
				}
				summary.DateTime = DateTime.Parse(headerMatch.Groups["LocalDateTime"].Value);

				lineIndex++;
				Match tableMatch = TableLineRegex.Match(lines[lineIndex]);
				if (tableMatch.Success)
				{
					summary.TableName = tableMatch.Groups["TableName"].Value;
					summary.ButtonNumber = uint.Parse(tableMatch.Groups["DealerSeatNumber"].Value);
					summary.SeatCount = uint.Parse(tableMatch.Groups["SeatCount"].Value);

					lineIndex++;
					Match seatMatch = SeatLineRegex.Match(lines[lineIndex]);
					while (seatMatch.Success)
					{
						summary.SetSeat
						(
							int.Parse(seatMatch.Groups["SeatNumber"].Value),
							seatMatch.Groups["PlayerName"].Value,
							ParseAmount(seatMatch.Groups["PlayerStack"].Value)
						);
						lineIndex++;
						seatMatch = SeatLineRegex.Match(lines[lineIndex]);
					}

					summary.SetStreet(Enums.PokerStreetType.PreFlop);

					Match startMatch = ReadStartAction(summary, lines[lineIndex]);
					while (startMatch.Success)
					{
						lineIndex++;
						startMatch = ReadStartAction(summary, lines[lineIndex]);
					}

					Match holeCardsMatch = HoleCardStreetLineRegex.Match(lines[lineIndex]);
					holeCardsMatch = HoleCardStreetLineRegex.Match(lines[lineIndex]);
					if (!holeCardsMatch.Success)
						throw new Exception("Excepting :" + HoleCardStreetLineRegex + " and have: " + lines[lineIndex]);
					lineIndex++;

					Match dealtHoleCardsMatch = DealtHoleCardLineRegex.Match(lines[lineIndex]);
					if (dealtHoleCardsMatch.Success)
					{
						summary.SetHoleCards(dealtHoleCardsMatch.Groups["PlayerName"].Value, Card.ParseArray(dealtHoleCardsMatch.Groups["HoleCards"].Value));
						lineIndex++;
					}

					Match actionMatch = ReadAction(summary, lines[lineIndex]);
					while (actionMatch.Success)
					{
						lineIndex++;
						actionMatch = ReadAction(summary, lines[lineIndex]);
					}

					actionMatch = ReadEndAction(summary, lines[lineIndex]);
					while (actionMatch.Success)
					{
						lineIndex++;
						actionMatch = ReadEndAction(summary, lines[lineIndex]);
					}

					Match summaryMatch = SummaryStreetLineRegex.Match(lines[lineIndex]);
					if (!summaryMatch.Success)
					{
						Match flopMatch = FlopStreetLineRegex.Match(lines[lineIndex]);
						if (!flopMatch.Success)
							throw new Exception("Excepting :" + FlopStreetLineRegex + " and have: " + lines[lineIndex]);
						summary.SetStreet(Enums.PokerStreetType.Flop, Card.ParseArray(flopMatch.Groups["FlopCards"].Value));

						lineIndex++;
						actionMatch = ReadAction(summary, lines[lineIndex]);
						while (actionMatch.Success)
						{
							lineIndex++;
							actionMatch = ReadAction(summary, lines[lineIndex]);
						}

						actionMatch = ReadEndAction(summary, lines[lineIndex]);
						while (actionMatch.Success)
						{
							lineIndex++;
							actionMatch = ReadEndAction(summary, lines[lineIndex]);
						}

						summaryMatch = SummaryStreetLineRegex.Match(lines[lineIndex]);
						if (!summaryMatch.Success)
						{
							Match turnMatch = TurnStreetLineRegex.Match(lines[lineIndex]);
							if(!turnMatch.Success)
								throw new Exception("Excepting :" + TurnStreetLineRegex + " and have: " + lines[lineIndex]);
							summary.SetStreet(Enums.PokerStreetType.Turn, Card.Parse(turnMatch.Groups["TurnCard"].Value));

							lineIndex++;
							actionMatch = ReadAction(summary, lines[lineIndex]);
							while (actionMatch.Success)
							{
								lineIndex++;
								actionMatch = ReadAction(summary, lines[lineIndex]);
							}

							actionMatch = ReadEndAction(summary, lines[lineIndex]);
							while (actionMatch.Success)
							{
								lineIndex++;
								actionMatch = ReadEndAction(summary, lines[lineIndex]);
							}
							
							summaryMatch = SummaryStreetLineRegex.Match(lines[lineIndex]);
							if (!summaryMatch.Success)
							{
								Match riverMatch = RiverStreetLineRegex.Match(lines[lineIndex]);
								if (!riverMatch.Success)
									throw new Exception("Excepting :" + RiverStreetLineRegex + " and have: " + lines[lineIndex]);
								summary.SetStreet(Enums.PokerStreetType.River, Card.Parse(riverMatch.Groups["RiverCard"].Value));

								lineIndex++;
								actionMatch = ReadAction(summary, lines[lineIndex]);
								while (actionMatch.Success)
								{
									lineIndex++;
									actionMatch = ReadAction(summary, lines[lineIndex]);
								}

								actionMatch = ReadEndAction(summary, lines[lineIndex]);
								while (actionMatch.Success)
								{
									lineIndex++;
									actionMatch = ReadEndAction(summary, lines[lineIndex]);
								}
								
								summaryMatch = SummaryStreetLineRegex.Match(lines[lineIndex]);
								if (!summaryMatch.Success)
								{
									Match showDownMatch = ShowDownStreetLineRegex.Match(lines[lineIndex]);
									if (!showDownMatch.Success)
										throw new Exception("Excepting :" + ShowDownStreetLineRegex + " and have: " + lines[lineIndex]);
									summary.Showdown = true;
									summary.SetStreet(Enums.PokerStreetType.Showdown);

									lineIndex++;
									Match showMatch = ReadShowAction(summary, lines[lineIndex]);
									while (showMatch.Success)
									{
										lineIndex++;
										showMatch = ReadShowAction(summary, lines[lineIndex]);
									}

									actionMatch = ReadEndAction(summary, lines[lineIndex]);
									while (actionMatch.Success)
									{
										lineIndex++;
										actionMatch = ReadEndAction(summary, lines[lineIndex]);
									}
									
									summaryMatch = SummaryStreetLineRegex.Match(lines[lineIndex]);
									if (!summaryMatch.Success)
										throw new Exception("Excepting :" + SummaryStreetLineRegex + " and have: " + lines[lineIndex]);
								}
							}
						}
					}

					lineIndex++;
					Match totalPotLine = TotalPotLineRegex.Match(lines[lineIndex]);
					if (!totalPotLine.Success)
						throw new Exception("Excepting :" + TotalPotLineRegex + " and have: " + lines[lineIndex]);
					summary.Rake = (ulong)Math.Round(ParseAmount(totalPotLine.Groups["RakeAmount"].Value) * 100);
					summary.TotalPot = (ulong)Math.Round(ParseAmount(totalPotLine.Groups["Amount"].Value) * 100);

					if (summary.TotalPot != summary.Pot.TotalAmount)
						throw new Exception("Invalid calculations");

					// skip unknow lines
					while (lineIndex < lines.Length && !string.IsNullOrWhiteSpace(lines[lineIndex]))
						lineIndex++;

					// skip whitespaces
					while (lineIndex < lines.Length && string.IsNullOrWhiteSpace(lines[lineIndex]))
						lineIndex++;
				}
				else
					throw new Exception("Excepting :" + TableLineRegex + " and have: " + lines[lineIndex]);

				foreach (KeyValuePair<string, CardList> pair in summary.HoleCards)
				{
					PokerHighHand highHand = PokerHighHand.GetBestHand(pair.Value, summary.CommunityCards);
					summary.HandsResult.Add(pair.Key, highHand);
				}
				foreach (TexasHoldemHandSummaryLegacy.SeatInformation seat in summary.Seats)
					if (seat != null)
						summary.GetBalance(seat.PlayerName);

				return summary;
			}
			else
				throw new Exception("Excepting :" + HeaderLineRegex + " and have: " + lines[lineIndex]);
		}
	}
}
